package com.lagou.springexp;

import com.lagou.annotation.ClientRpcService;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

import java.util.Set;

/**
 * @ClassName ClassPathServiceScanner
 * @Description
 * @Author playboy
 * @Date 2021/6/5 5:39 下午
 * @Version 1.0
 **/
public class ClassPathServiceScanner extends ClassPathBeanDefinitionScanner {

	private Class<? extends ServiceFactoryBean> serviceFactoryBeanClass;

	public void setServiceFactoryBeanClass(Class<? extends ServiceFactoryBean> serviceFactoryBeanClass) {
		this.serviceFactoryBeanClass = serviceFactoryBeanClass;
	}

	public ClassPathServiceScanner(BeanDefinitionRegistry registry) {
		super(registry);
	}

	public void registerFilters() {
		addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
	}

	/**
	 * 复习doScan方法,扫描完成之后
	 *
	 * @param basePackages
	 * @return
	 */
	@Override
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

		if (!beanDefinitions.isEmpty()) {
			processBeanDefinitions(beanDefinitions);
		}

		return beanDefinitions;
	}

	/**
	 * 覆写isCandidateComponent这个方法，它的作用是让扫描只扫描接口
	 * 父类的判断条件是不处理扫描到的接口
	 *
	 * @param beanDefinition
	 * @return
	 */
	@Override
	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
		return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
	}

	/**
	 * 该方法的作用就是将扫描到的接口，指定它的beanClass为一个工厂类
	 *
	 * @param beanDefinitions
	 */
	private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
		beanDefinitions.forEach(beanDefinitionHolder -> {
			GenericBeanDefinition definition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
			String beanClassName = definition.getBeanClassName();
			try {
				Class<?> aClass = Class.forName(beanClassName);
				if (aClass.isAnnotationPresent(ClientRpcService.class)) {
					definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
					definition.getPropertyValues().add("rpcProxy",
							new RuntimeBeanReference("rpcProxy"));
					definition.setBeanClass(this.serviceFactoryBeanClass);
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}

		});
	}
}
